//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <iostream>
#include <fstream>

#include "ListAncestorMol.h"
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define TYPE_COINCIDENCE 1
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
namespace SpaceCorelationClusters {

  bool AscendentAncestor(TNode <AncestorMol>* NodeT, void* ref, void* parameters) {
    AncestorMol* ancestorA  = NodeT->Info();
    AncestorMol* ancestorB  = ((TNode <AncestorMol>*)ref)->Info();
    int          level      = (*(int*)parameters) - 1;
    return (*(ancestorA->ListIdAncestor()->Get(level)) < *(ancestorB->ListIdAncestor()->Get(level)))?true:false;
  }

  bool DiffAncestor(TNode <AncestorMol>* NodeT, void* ref, void* parameters) {
    AncestorMol* ancestorA  = NodeT->Info();
    AncestorMol* ancestorB  = ((TNode <AncestorMol>*)ref)->Info();
    int          level      = (*(int*)parameters) - 1;
    if (*(ancestorA->ListIdAncestor()->Get(level)) != *(ancestorB->ListIdAncestor()->Get(level))) return false;
    else {
      if (*(ancestorA->ListIdAncestor()->Get(level)) == *(ancestorA->ListIdAncestor()->Get(0))) {
        NodeT->Info(NULL);
        NodeT->Info(ancestorB);
        ((TNode <AncestorMol>*)ref)->Info(NULL);
        ((TNode <AncestorMol>*)ref)->Info(ancestorA);
      }
      return true;
    }
  }

  bool EqualAncestor(TNode <AncestorMol>* NodeT, void* ref, void* parameters) {
    AncestorMol* ancestorA  = NodeT->Info();
    AncestorMol* ancestorB  = ((TNode <AncestorMol>*)ref)->Info();
    int          level      = (*(int*)parameters) - 1;
    return (*(ancestorA->ListIdAncestor()->Get(level)) == *(ancestorB->ListIdAncestor()->Get(level)))?true:false;
  }

};
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int main(int argc, char** argv) {

  String* filenameCluster1In;
  String* filenameCluster2In;
  String* filenameOut;
  int     ancestorLevel1, ancestorLevel2;

  if (argc < 5) {
    cout << "Error in the input arguments. The execution must be: " << endl;
    cout << "./CorrelationClusters <Input Cluster File - 1> <#Ancestor Level - 1> <Input Cluster File - 2> <#Ancestor Level - 2> <Output File>" << endl;
    return 0;
  }
  else {
    cout << "---------------------------------------------------------------------------------" << endl;
    cout << " Input Cluster File - 1 : " << argv[1] << endl;
    cout << "    #Ancestor Level - 1 : " << argv[2] << endl;
    cout << " Input Cluster File - 2 : " << argv[3] << endl;
    cout << "    #Ancestor Level - 2 : " << argv[4] << endl;
    cout << "            Output File : " << argv[5] << endl;
    cout << "---------------------------------------------------------------------------------" << endl;
    filenameCluster1In = new String(argv[1]);
    ancestorLevel1     = atoi(argv[2]);
    filenameCluster2In = new String(argv[3]);
    ancestorLevel2     = atoi(argv[4]);
    filenameOut        = new String(argv[5]);
  }

  ListAncestorMol* ancestorCluster1 = new ListAncestorMol();
  ListAncestorMol* ancestorCluster2 = new ListAncestorMol();

  ancestorCluster1->FilenameAncestor(filenameCluster1In);
  ancestorCluster2->FilenameAncestor(filenameCluster2In);

  ancestorCluster1->LoadDataAncestorFiles();
  ancestorCluster2->LoadDataAncestorFiles();

  fstream fileOut;
  fileOut.open(filenameOut->Out(), fstream::out);

  for (int i = 0; i < 183; i++) { fileOut << "-"; cout << "-";  }
  cout << endl; fileOut << endl;
  
  fileOut.width(15); fileOut.right; fileOut << "Clusters" << " |";
  fileOut.width(10); fileOut.right; fileOut << "Level" << " |";
  fileOut.width(20); fileOut.right; fileOut << "Representative" << " |";
  fileOut.width(10); fileOut.right; fileOut << "Size" << " |";
  fileOut.width(10); fileOut.right; fileOut << "Level" << " |";
  fileOut.width(20); fileOut.right; fileOut << "Repre. Higher" << " |";
  fileOut.width(10); fileOut.right; fileOut << "Size" << " |";
  fileOut.width(20); fileOut.right; fileOut << "Ratio Size/Higher" << " |";
  fileOut.width(20); fileOut.right; fileOut << "Repre. Lower" << " |";
  fileOut.width(10); fileOut.right; fileOut << "Size" << " |";
  fileOut.width(20); fileOut.right; fileOut << "Ratio Size/Lower" << " |";
  fileOut << endl;

  cout.width(15); cout.right; cout << "Clusters" << " |";
  cout.width(10); cout.right; cout << "Level" << " |";
  cout.width(20); cout.right; cout << "Representative" << " |";
  cout.width(10); cout.right; cout << "Size" << " |";
  cout.width(20); cout.right; cout << "Repre. Higher" << " |";
  cout.width(10); cout.right; cout << "Size" << " |";
  cout.width(20); cout.right; cout << "Ratio Size/Higher" << " |";
  cout.width(20); cout.right; cout << "Repre. Lower" << " |";
  cout.width(10); cout.right; cout << "Size" << " |";
  cout.width(20); cout.right; cout << "Ratio Size/Lower" << " |";
  cout << endl;

  for (int i = 0; i < 175; i++) { fileOut << "-"; cout << "-";  }
  cout << endl; fileOut << endl;

  TListE <AncestorMol> *representativeAncestorList = new TListE <AncestorMol>;

  ancestorCluster1->ListAncestor()->QuickSortList(SpaceCorelationClusters::AscendentAncestor, NULL,  &ancestorLevel1);
  ancestorCluster1->ListAncestor()->RepresentativeOcurrencesAfterOrdered(SpaceCorelationClusters::DiffAncestor, representativeAncestorList, &ancestorLevel1);

  int    counterCluster = 0;
  double totalScore, cumulativeScore = 0;

  if (representativeAncestorList->Length()) {

    representativeAncestorList->SetInitial();

    while (representativeAncestorList->SetNext()) {

      TListE <AncestorMol> *clusterList1 = new TListE <AncestorMol>;
      TListE <AncestorMol> *clusterList2 = new TListE <AncestorMol>;

      ancestorCluster1->ListAncestor()->AllOcurrence(SpaceCorelationClusters::EqualAncestor, clusterList1, representativeAncestorList->GetCurrentNode(), &ancestorLevel1);

      int clusterLengthSearch = clusterList1->Length();

      clusterList1->SetInitial();

      while (clusterList1->SetNext()) {

        int levelSearch = 1;
        //cout << "Search: " << clusterList1->GetCurrent()->ListIdAncestor()->Get(levelSearch - 1)->Out() << endl;
        AncestorMol* resultSearch = ancestorCluster2->ListAncestor()->FirstOcurrence(SpaceCorelationClusters::EqualAncestor, clusterList1->GetCurrentNode(), &levelSearch);

        if (resultSearch) 
          clusterList2->Add(resultSearch);
        else {
          clusterLengthSearch--;
          //cout << "Error search the item: " << clusterList1->GetCurrent()->ListIdAncestor()->Get(0)->Out() << endl;
        }
        
      }

      clusterList2->QuickSortList(SpaceCorelationClusters::AscendentAncestor, NULL, &ancestorLevel2);

      int     higherNumberCoincidence = 0;
      int     lowerNumberCoincidence  = clusterList2->Length();
      int     sizeCoincidence         = 0;

      String* higherIDCoincidence     = new String();
      String* lowerIDCoincidence      = new String();
      String  compare;

      compare.In("");

      clusterList2->SetInitial();

      while (clusterList2->SetNext()) {
        if (strcmp(clusterList2->GetCurrent()->ListIdAncestor()->Get(ancestorLevel2 - 1)->Out(), compare.Out())) {
          if (sizeCoincidence >= higherNumberCoincidence && compare.Length()) {
            higherNumberCoincidence = sizeCoincidence;
            higherIDCoincidence->In(compare);
          }
          if (sizeCoincidence <= lowerNumberCoincidence && compare.Length()) {
            lowerNumberCoincidence = sizeCoincidence;
            lowerIDCoincidence->In(compare);
          }
          compare.In(clusterList2->GetCurrent()->ListIdAncestor()->Get(ancestorLevel2 - 1)->Out());
          sizeCoincidence = 0;
        }
        sizeCoincidence++;
      }

      if (sizeCoincidence >= higherNumberCoincidence) {
        higherNumberCoincidence = sizeCoincidence;
        higherIDCoincidence->In(compare);
      }
      if (sizeCoincidence <= lowerNumberCoincidence) {
        lowerNumberCoincidence = sizeCoincidence;
        lowerIDCoincidence->In(compare);
      }

      counterCluster++;

      double ratioHigher = (clusterList2->Length())?(double)((double)higherNumberCoincidence/(double)clusterList2->Length()):0;
      double ratioLower  = (clusterList2->Length())?(double)((double)lowerNumberCoincidence/(double)clusterList2->Length()):0;

      cumulativeScore += ratioHigher;

      //Output FILE
      fileOut.width(15); fileOut.right; fileOut << counterCluster << " |";
      fileOut.width(10); fileOut.right; fileOut << ancestorLevel1 << " |";
      fileOut.width(20); fileOut.right; fileOut << representativeAncestorList->GetCurrent()->ListIdAncestor()->Get(ancestorLevel1 - 1)->Out() << " |";
      fileOut.width(10); fileOut.right; fileOut << clusterList1->Length() << " |";
      fileOut.width(20); fileOut.right; fileOut << higherIDCoincidence->Out() << " |";
      fileOut.width(10); fileOut.right; fileOut << higherNumberCoincidence << " |";
      fileOut.width(20); fileOut.right; fileOut << ratioHigher << " |";
      fileOut.width(20); fileOut.right; fileOut << lowerIDCoincidence->Out() << " |";
      fileOut.width(10); fileOut.right; fileOut << lowerNumberCoincidence << " |";
      fileOut.width(20); fileOut.right; fileOut << ratioLower << " |";
      fileOut << endl;
      
      cout.width(15); cout.right; cout << counterCluster << " |";
      cout.width(10); cout.right; cout << ancestorLevel1 << " |";
      cout.width(20); cout.right; cout << representativeAncestorList->GetCurrent()->ListIdAncestor()->Get(ancestorLevel1 - 1)->Out() << " |";
      cout.width(10); cout.right; cout << clusterList1->Length() << " |";
      cout.width(20); cout.right; cout << higherIDCoincidence->Out() << " |";
      cout.width(10); cout.right; cout << higherNumberCoincidence << " |";
      cout.width(20); cout.right; cout << ratioHigher << " |";
      cout.width(20); cout.right; cout << lowerIDCoincidence->Out() << " |";
      cout.width(10); cout.right; cout << lowerNumberCoincidence << " |";
      cout.width(20); cout.right; cout << ratioLower << " |";
      cout << endl;

      clusterList1->TransferAll();
      clusterList2->TransferAll();

      if (clusterList1)         delete clusterList1;
      if (clusterList2)         delete clusterList2;

      if (higherIDCoincidence)  delete higherIDCoincidence;
      if (lowerIDCoincidence)   delete lowerIDCoincidence;
      
    }

    totalScore = (double)((double)cumulativeScore/(double)representativeAncestorList->Length());

    representativeAncestorList->TransferAll();

    if (representativeAncestorList) delete representativeAncestorList;

  }

  fileOut.close();
  
  if (ancestorCluster1) delete ancestorCluster1;
  if (ancestorCluster2) delete ancestorCluster2;

  for (int i = 0; i < 175; i++) cout << "-"; cout << endl;
  cout << "Total Score = " << totalScore << endl;

  return 1;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//




